package com.boarsoft.boar.config.var.action;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.boarsoft.bean.ReplyInfo;
import com.boarsoft.boar.BaseConfig;
import com.boarsoft.boar.app.AppBiz;
import com.boarsoft.boar.app.AppInstBiz;
import com.boarsoft.boar.config.entity.ConfigVar;
import com.boarsoft.boar.config.service.ConfigVarService;
import com.boarsoft.boar.config.var.ConfigVarAdapter;
import com.boarsoft.boar.config.var.ConfigVarAppBiz;
import com.boarsoft.boar.config.var.ConfigVarBiz;
import com.boarsoft.boar.config.var.ConfigVarEnvBiz;
import com.boarsoft.boar.entity.AppInfo;
import com.boarsoft.common.dao.PagedResult;
import com.boarsoft.common.util.StringUtil;
import com.boarsoft.common.util.ZipUtil;
import com.boarsoft.config.core.ConfigVarSync;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@RestController
@RequestMapping("/var")
public class ConfigVarAction {
	@Autowired
	protected ConfigVarBiz configVarBiz;
	@Autowired
	protected ConfigVarAppBiz configVarAppBiz;
	@Autowired
	protected ConfigVarSync configVarSync;
	@Autowired
	protected AppInstBiz appInstBiz;
	@Autowired
	protected AppBiz appBiz;
	@Autowired
	protected ConfigVarEnvBiz configVarEnvBiz;
	@Autowired
	protected ConfigVarAdapter configVarAdapter;
	@Autowired
	protected ConfigVarService configVarService;

	@JsonIgnoreProperties({ "apps" })
	@RequestMapping("/list2.do")
	//@Authorized(code = "config.var.list")
	public ReplyInfo<Object> listAll(String appId, String env, String appCode ,HttpServletRequest request) {
		if(appId==null){
			AppInfo appInfo=appBiz.find(appCode);
			appId=appInfo.getId();
		}
		List<ConfigVar> configVars;
		if (StringUtil.isBlank(env)) {
			configVars = configVarBiz.listWithoutEnv(appId);
		}else{
			configVars = configVarBiz.list2(appId, env);
		}

		for (ConfigVar configVar : configVars) {
			configVar.setAppId(appId);
			configVar.setEnv(env);
			configVar.setApps(null);
		}
		return new ReplyInfo<>(true, configVars);
	}

	@JsonIgnoreProperties({ "apps" })
	@RequestMapping("/list.do")
	public ReplyInfo<Object> list(String projId,String appId, String key, String env, int pageNo, int pageSize, String orderBy) {
		if (StringUtil.isBlank(appId)) {
			return new ReplyInfo<>(false, "应用编码不能为空");
		}
		PagedResult<ConfigVar> pr = configVarBiz.list2Env(projId, appId,key, env, pageNo, pageSize, orderBy);
		return new ReplyInfo<>(true, pr);
	}


	/**
	 * 从drm拉取全部配置
	 * @param group 资源id
	 * @return
	 */
	@RequestMapping("/listDrm.do")
	//@Authorized(code = "config.var.listAll")
	@JsonIgnoreProperties({ "apps" })
	public ReplyInfo<Object> listAll(String appId,String env,String group) {
		return new ReplyInfo<>(true,configVarAdapter.locateProcessor("drm").list(appId,env,group));
	}

	/**
	 *
	 *	参数变更推送
	 *
	 * */
	@RequestMapping("/put.do")
	//@Authorized(code = "config.var.put")
	public ReplyInfo<Object> put(ConfigVar cv) {
		configVarAdapter.locateProcessor(cv.getStore()).put(cv);
		return new ReplyInfo<>(true);
	}


	@RequestMapping("/save.do")
	//@Authorized(code = "config.var.save")
	public ReplyInfo<Object> save(ConfigVar cv) {
		if(cv.getAppId()==null&&cv.getAppCode()!=null){
			AppInfo appInfo=appBiz.find(cv.getAppCode());
			if(appInfo==null){
				return new ReplyInfo<>(false,"应用编码["+cv.getAppCode()+"]不存在");
			}
			cv.setAppId(appInfo.getId());
			cv.setProjId(appInfo.getProjId());
		}
		if(cv.getVer()==null){
			cv.setVer("default");
		}
		//1.根据store（存储介质）决定需要调用具体的组件
		configVarAdapter.locateProcessor(cv.getStore()).save(cv);
		return ReplyInfo.SUCCESS;
	}

	@RequestMapping("/delete.do")
	//@Authorized(code = "config.var.delete")
	public ReplyInfo<Object> delete(ConfigVar cv) {
		configVarAdapter.locateProcessor(cv.getStore()).delete(cv);
		return ReplyInfo.SUCCESS;
	}

	@RequestMapping("/add.do")
	//@Authorized(code = "config.var.add")
	public ReplyInfo<Object> add(ConfigVar o) {
		configVarBiz.add(o);
		return this.put(o);
	}

	@RequestMapping("/update.do")
	//@Authorized(code = "config.var.update")
	public ReplyInfo<Object> update(ConfigVar cv) {
		configVarAdapter.locateProcessor(cv.getStore()).save(cv);
		//return this.put(configVar);
		return ReplyInfo.SUCCESS;
	}

	@RequestMapping("/clone.do")
	public ReplyInfo<Object> clone(String appId, String fromEnv,String toEnv) {
		//1.调用参数服务进行参数克隆
		configVarService.clone(appId,fromEnv,toEnv);
		return new ReplyInfo<>(true,"SUCCESS");
	}

	@RequestMapping("/export.do")
	public ResponseEntity<Resource> configExport(String appId, String fromEnv)
			throws FileNotFoundException, MalformedURLException {
		if(appId==null){
			throw new RuntimeException("appId cannot be null");
		}
		//1.设置导出根目录
		StringBuilder sb=new StringBuilder(BaseConfig.PATH_PRIVATE);
		String exportRoot=sb.append("/").append("configexport")
				.append("/").append(System.currentTimeMillis()).toString();
		if(!new File(exportRoot).exists()){
			new File(exportRoot).mkdirs();
		}
		AppInfo appInfo=appBiz.get(appId);
		String fileName=exportRoot+"_"+appInfo.getCode()+"_"+fromEnv+".zip";
		//2.导出配置变量
		configVarService.exportConfig(appId,fromEnv,exportRoot);
		//4.将根目录打成zip包
		ZipUtil.zip(fileName,exportRoot);
		Path path = Paths.get(fileName);
		Resource resource = new UrlResource(path.toUri());
		return ResponseEntity.ok()
				.header("Content-Disposition", "attachment; filename=" + resource.getFilename())
				.body(resource);
	}

	@RequestMapping("/import.do")
	public ReplyInfo<Object> configImport(@RequestParam("file") MultipartFile zipFile) throws IOException {

		try {
			// 获取ZIP文件的输入流
			InputStream zipInputStream = zipFile.getInputStream();
			ZipInputStream zis = new ZipInputStream(zipInputStream);

			// 解压ZIP文件的条目
			ZipEntry zipEntry = zis.getNextEntry();
			String targetDirectory=new StringBuilder(BaseConfig.PATH_PRIVATE)
					.append("/")
					.append("configimport")
					.append("/").toString();
			if(!new File(targetDirectory).exists()){
				new File(targetDirectory).mkdirs();
			}
			String zipFileNm=targetDirectory;
			while (zipEntry != null) {
				String fileName = zipEntry.getName();
				File newFile = newFile(new File(targetDirectory), fileName); // 目标目录应该存在
				if(fileName.endsWith(".data")){
					zipFileNm+=fileName;
				}
				if (zipEntry.isDirectory()) {
					if (!newFile.isDirectory() && !newFile.mkdirs()) {
						throw new IOException("Failed to create directory " + newFile);
					}
				} else {
					// 为文件创建所有父目录
					File parent = newFile.getParentFile();
					if (!parent.isDirectory() && !parent.mkdirs()) {
						throw new IOException("Failed to create directory " + parent);
					}

					// 将ZIP文件内容写入文件
					FileOutputStream fos = new FileOutputStream(newFile);
					BufferedOutputStream bos = new BufferedOutputStream(fos);
					byte[] bytesIn = new byte[4096];
					int read = 0;
					while ((read = zis.read(bytesIn)) != -1) {
						bos.write(bytesIn, 0, read);
					}
					bos.close();
				}
				zipEntry = zis.getNextEntry();
			}
			//2.找到配置变量目录,导入配置变量
			configVarService.importConfig(zipFileNm);
			zis.closeEntry();
			zis.close();
			return new ReplyInfo<>(true,"success");
		} catch (Exception e) {
			e.printStackTrace();
			return new ReplyInfo<>(false,e.getMessage());
		}
	}

	public File newFile(File destinationDir, String fileName) throws IOException {
		File destFile = new File(destinationDir, fileName);

		String destDirPath = destinationDir.getCanonicalPath();
		String destFilePath = destFile.getCanonicalPath();

		if (!destFilePath.startsWith(destDirPath + File.separator)) {
			throw new IOException("Entry is outside of the target dir: " + fileName);
		}

		return destFile;
	}


}